package com.cakebackoffice.clientsoap;

import com.cakebackoffice.clientsoap.Exception.SoapClientException;
import com.cakebackoffice.clientsoap.Exception.SoapComException;
import com.cakebackoffice.clientsoap.contract.ContractObject;
import com.cakebackoffice.clientsoap.contract.SoapArray;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class Call {

    public Call(String soapAction, String methodName, String namespace, String uri, Boolean dotNet) {
        setSoapAction(soapAction);
        setMethodName(methodName);
        setNamespace(namespace);
        setUri(uri);
        setDotNet(dotNet);
    }

    private String soapAction;              //action name on webservice
    private String methodName;              //method name to call
    private String namespace;               //namespace
    private String uri;                     //path(wsdl, asmx..)
    private Boolean dotNet;                 //is .NET?
    private Map<String, Object> parameters;
    private Map<String, Class> toMap = new HashMap<String, Class>();

    public String getSoapAction() {
        return soapAction;
    }

    public void setSoapAction(String soapAction) {
        this.soapAction = soapAction;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    public String getNamespace() {
        return namespace;
    }

    public void setNamespace(String namespace) {
        this.namespace = namespace;
    }

    public String getUri() {
        return uri;
    }

    public void setUri(String uri) {
        this.uri = uri;
    }

    public Map<String, Object> getParameters() {
        return parameters;
    }

    public void setParameters(Map<String, Object> parameters) {
        this.parameters = parameters;
    }

    public Boolean getDotNet() {
        return dotNet;
    }

    public void setDotNet(Boolean dotNet) {
        this.dotNet = dotNet;
    }

    public void addParameter(String parameterName, Object parameterValue) {
        if (getParameters() == null) {
            this.parameters = new HashMap<String, Object>();
        }
        getParameters().put(parameterName, parameterValue);
    }

    public void addParameter(Map<String, Object> parameters) {
        if (parameters != null && parameters.size() > 0) {
            if (getParameters() == null) {
                this.parameters = new HashMap<String, Object>();
            }
            getParameters().putAll(parameters);
        }
    }

    public Map<String, Class> getToMap() {
        return toMap;
    }

    public void setToMap(Map<String, Class> toMap) {
        this.toMap = toMap;
    }

    public Object executeCallResponse() throws SoapClientException, SoapComException {
        Object result = null;
        SoapObject request = new SoapObject(getNamespace(), getMethodName()); //create the soap method

        if (getParameters() != null) {
            for (Map.Entry<String, Object> property : getParameters().entrySet()) {
                addPropertyToRequest(property.getKey(), property.getValue(), request);
            }
            getParameters().clear();
        }

        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); //serialize the envelope
        envelope.dotNet = getDotNet();
        envelope.setOutputSoapObject(request); //this method will return a response

        if (getToMap() != null) {
            for (Map.Entry<String, Class> toMap : getToMap().entrySet()) {
                envelope.addMapping(getNamespace(), toMap.getKey(), toMap.getValue());
            }
        }

        HttpTransportSE androidHttpTransport = new HttpTransportSE(getUri()); //open the requisition
        androidHttpTransport.debug = true;
        try {
            androidHttpTransport.call(getSoapAction(), envelope);// call
        } catch (IOException e) {
            SoapComException sce = new SoapComException(e.getMessage());
            sce.setStackTrace(e.getStackTrace());
            throw sce;
        } catch (XmlPullParserException e) {
            SoapClientException sce = new SoapClientException(SoapClientException.PARSING_EXCEPTION);
            sce.setStackTrace(e.getStackTrace());
            throw sce;
        }
        try {
            result = envelope.getResponse(); // returns result of method called
        } catch (Exception e) {
            throw new SoapClientException(e.getMessage());
        }

        return result;
    }

    private void addPropertyToRequest(String key, Object value, SoapObject request) {
        if (value.getClass().isPrimitive() || value instanceof String || value instanceof Number) {
            request.addProperty(key, value);
        } else {
            if (value instanceof SoapArray) {
                request.addSoapObject(((SoapArray) value).toSoapObject(getNamespace(), key));
            } else {
                request.addProperty(((ContractObject) value).toPropertyInfo(key));
                String[] className = value.getClass().getName().split("contract.");
                getToMap().put(className[className.length - 1], value.getClass());
            }
        }
    }

    public void executeCall() throws Exception {
        SoapObject request = new SoapObject(getNamespace(), getMethodName()); //create the soap method

        if (getParameters() != null) {
            for (Map.Entry<String, Object> property : getParameters().entrySet()) {
                addPropertyToRequest(property.getKey(), property.getValue(), request);
            }
            getParameters().clear();
        }

        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); //serialize the envelope
        envelope.dotNet = getDotNet();
        HttpTransportSE androidHttpTransport = new HttpTransportSE(getUri()); //open the requisition
        androidHttpTransport.call(getSoapAction(), envelope);// call

    }

}